local mis_uu       = require('modules.commhm.utils')
local mis_config   = require('mis_config');
local mis_rank     = require('mis_rank')
local mis_frashsale = require('mis_frashsale')
local mis_data     = nil
local mis_log      = nil
local mis_bridge   = nil
local mis_common   = nil
local mis_extend   = nil
local t_retCode    = nil
local t_retCodeMsg = nil

local ngx = ngx
local type = type
local pairs = pairs
local table = table
local math = math
local math_max = math.max
local math_min = math.min
local tonumber = tonumber
local tostring = tostring
local table_insert = table.insert

-- 觉醒活动
local this = {
	s_name = string.match(debug.getinfo(1).short_src, '.*/(.*).lua');	-- 模块名称
}

this.log = function (msg)
	mis_log.day(this.s_name, msg)
end

local new_awakening_profile = function ()
	return {
		level = 1,
		vanityCoin = 0,
		originCoin = 0,
	}
end

local update_cloud_server_room = function (t_user, t_userData)
	local t_taskConf = mis_data.t_awakening_activity
	if not t_taskConf
	or not t_taskConf.t_conf
	or not t_taskConf.t_conf.t_map then
		return false, 'map is not exist!'
	end

	for mapID, _ in pairs(t_taskConf.t_conf.t_map or {}) do
		local namespace = 'activity_awakening:global'
		local key       = 'lv_' .. t_user.n_uin
		local val       = tostring(t_userData.awakening.level)
		if not mis_bridge.set_cloud_dhs_data(mapID, namespace, key, val) then
			this.log( 'awakening cloud dhs updata fault' .. mis_uu.to_str({
				namespace = namespace,
				mapID = mapID,
				key   = key,
				value = val,
			}))
		end
	end
	return true
end

local get_awakening_profile = function (t_user, t_userData)
	if mis_uu.tableIsEmpty(t_userData.awakening or {}) then
		t_userData.awakening = new_awakening_profile()
		update_cloud_server_room(t_user, t_userData)
	end
	-- 数据修复
	t_userData.awakening.level = t_userData.awakening.level or 1
	t_userData.awakening.vanityCoin = t_userData.awakening.vanityCoin or 0
	t_userData.awakening.originCoin = t_userData.awakening.originCoin or 0
	return {
		level        = t_userData.awakening.level,			-- 等级
		vanityCoin   = t_userData.awakening.vanityCoin,		-- 虚无之力
		originCoin   = t_userData.awakening.originCoin,		-- 起源之力
		exchange_num = t_userData.exchange_num or 0,		-- 奖券数
	}
end


local itemOp = {
	ADD = 1,
	DEC = 2,
}
local itemFunc = {
	-- 奖券
	[mis_config.t_specialItem.s_SHARE] = {
		[itemOp.ADD] = function (t_userData, item)
			t_userData.exchange_num = (t_userData.exchange_num or 0) + item.num
			return t_retCode.n_OK
		end,
		[itemOp.DEC] = function (t_userData, item)
			if not t_userData.exchange_num or item.num > (t_userData.exchange_num or 0) then
				return t_retCode.n_OPER_ERR, 'exchange_num not enough'
			end
			t_userData.exchange_num = t_userData.exchange_num - item.num
			return t_retCode.n_OK
		end
	},
	-- 虚空之力
	[mis_config.t_specialItem.s_SHARE02] = {
		[itemOp.ADD] = function (t_userData, item)
			t_userData.awakening = t_userData.awakening or {}
			t_userData.awakening.vanityCoin = (t_userData.awakening.vanityCoin or 0) + item.num
			return t_retCode.n_OK
		end,
		[itemOp.DEC] = function (t_userData, item)
			if not t_userData.awakening or item.num > (t_userData.awakening.vanityCoin or 0) then
				return t_retCode.n_OPER_ERR, 'vanityCoin not enough'
			end
			t_userData.awakening.vanityCoin = t_userData.awakening.vanityCoin - item.num
			return t_retCode.n_OK
		end
	},
	-- 起源之力
	[mis_config.t_specialItem.s_SHARE03] = {
		[itemOp.ADD] = function (t_userData, item)
			t_userData.awakening = t_userData.awakening or {}
			t_userData.awakening.originCoin = (t_userData.awakening.originCoin or 0) + item.num
			return t_retCode.n_OK
		end,
		[itemOp.DEC] = function (t_userData, item)
			if not t_userData.awakening or item.num > (t_userData.awakening.originCoin or 0) then
				return t_retCode.n_OPER_ERR, 'originCoin not enough'
			end
			t_userData.awakening.originCoin = (t_userData.awakening.originCoin or 0) - item.num
			return t_retCode.n_OK
		end
	}
}


-- 奖励处理
local add_awakening_item = function (t_userData, t_award)
	for _, item in pairs(t_award.share or {}) do
		if  itemFunc[item.id]
		and itemFunc[item.id][itemOp.ADD] then
			itemFunc[item.id][itemOp.ADD](t_userData, item)
		end
	end
end

-- 奖励处理
local dec_awakening_item = function (t_userData, t_award)
	for _, item in pairs(t_award.share or {}) do
		if  itemFunc[item.id]
		and itemFunc[item.id][itemOp.DEC] then
			local n_code, s_desc = itemFunc[item.id][itemOp.DEC](t_userData, item)
			if n_code ~= t_retCode.n_OK then
				return n_code, s_desc
			end
		end
	end
	return t_retCode.n_OK
end

local get_map_ranking = function (s_mapID)
	return mis_rank.instance('awakening_' .. s_mapID)
end

local awakening_map_status = function ( t_user, t_userData, t_resp )
	local n_nowtime  = mis_data.get_server_time()
	local t_taskConf = mis_data.t_awakening_activity or {}
	if t_taskConf.t_conf and t_taskConf.t_conf.t_map then
		t_resp.map = t_resp.map or {}
		t_userData.map = t_userData.map or {}

		for s_mapID, t_mapConf in pairs(t_taskConf.t_conf.t_map or {}) do

			t_userData.map[s_mapID] = t_userData.map[s_mapID] or {}
			local t_roleMap = t_userData.map[s_mapID]
			for s_itemID, t_limitConf in pairs(t_mapConf.t_awardLimit or {}) do
				-- 初始化
				t_roleMap.awardLimit = t_roleMap.awardLimit or {}
				t_roleMap.awardLimit[s_itemID] = t_roleMap.awardLimit[s_itemID] or {
					count = 0,
					refreshTime = n_nowtime,
				}

				-- 刷新数据
				local t_itemLimit = t_roleMap.awardLimit[s_itemID]
				if t_limitConf.b_dailyLimit and mis_common.is_another_day(t_itemLimit.refreshTime, n_nowtime) then
					t_itemLimit.count = 0
					t_itemLimit.refreshTime = n_nowtime
				end

				-- 返回客户端数据
				t_resp.map[s_mapID] = t_resp.map[s_mapID] or { award_limit = {}}
				local t_awardLimit = t_resp.map[s_mapID].award_limit
				t_awardLimit[#t_awardLimit + 1] = {
					itemid = s_itemID,
					count  = t_itemLimit.count,
					limit  = t_limitConf.n_limit,
				}
			end
		end
	end
end

local create_movie_tickets = function (uin, num)
	if mis_data.t_awakening_tickets.n_status ~= mis_config.t_workStatus.n_ENABLE then
		mis_log.debug('t_awakening_ticket not init')
		return nil, t_retCode.n_WORK_ERR
	end

	local frashsale = mis_frashsale:inst(mis_config.t_workType.s_AWAKENING_ACTIVITY)
	if not frashsale then
		mis_log.debug('mis_frashsale not found')
		return nil, t_retCode.n_WORK_ERR
	end

	local tickets, empty = frashsale:Get(uin, num)
	this.log('create_movie_tickets' .. mis_uu.to_str({uin = uin, tickets = tickets, empty = empty}))

	if not tickets and not empty then
		return nil, t_retCode.n_HOT_ACTIVITY_AHEAD		-- 请重试
	elseif not tickets then
		return nil, t_retCode.n_SHARE_NO_ROLL_COUNT		-- 兑换完
	end
	return tickets
end

local get_movie_ticktet_remian = function ()
	local frashsale = mis_frashsale:inst(mis_config.t_workType.s_AWAKENING_ACTIVITY)
	if not frashsale then
		return nil
	end
	return frashsale.remain
end

local awakening_movies_status = function (t_user, t_userData, t_resp)
	t_resp.tickets = t_resp.tickets or {}
	if t_userData.movies and t_userData.movies.tickets then
		t_resp.tickets.t_tickets = t_userData.movies.tickets
	end

	local t_ticketConf = mis_data.t_awakening_tickets or {}
	if t_ticketConf.n_status == mis_config.t_workStatus.n_ENABLE then
		t_resp.tickets.total  = t_ticketConf.t_conf.total
		t_resp.tickets.remain = get_movie_ticktet_remian() or 0
	end
end


-- 获取活动主页数据
this.share_mission_status = function ( t_user, t_userData, t_award, t_resp, n_exchangeType )
	-- 活动奖励处理
	add_awakening_item(t_userData, t_award)
	-- 活动数据
	t_resp.profile = get_awakening_profile(t_user, t_userData)

	if ngx.ctx.t_params.mission_type == mis_config.t_workType.s_AWAKENING_HOMEPAGE then
		-- 首页返回副本信息
		awakening_map_status( t_user, t_userData, t_resp )
	end

	return t_retCode.n_OK
end

-- 活动奖励自动到账
local share_mission_award_check = function (t_user, t_userData, t_resp)
	local t_params  		= ngx.ctx.t_params
	local n_event			= t_params.event
	local s_type			= t_params.mission_type
	local t_taskConf 		= mis_data.t_share_mission[s_type]
	if not (t_taskConf and t_taskConf.t_conf) then
		return false, 'The mission is not exist!'
	end

	-- 是否自动领奖
	if not t_taskConf.t_conf.b_auto then
		return false, 'do not need auto get award'
	end

	-- 仅检测当前事件触发的任务
	local t_temp = t_taskConf.t_conf
	local t_mission = t_temp.t_mission[n_event]
	if mis_uu.tableIsEmpty(t_mission or {}) then
		return false, "mission not exist"
	end

	local t_autoAward = {share = {}, items = {}}
	for _, t_subTask in pairs(t_mission) do
		local t_usrTask = t_userData.tasks[s_type][t_subTask.n_subTaskId]
		if t_usrTask and t_usrTask.status == 1 and t_usrTask.progress >= t_subTask.n_target then
			-- 自动发奖
			if mis_extend.missionAwardCore[s_type] then
				-- 业务自定义处理
				mis_extend.missionAwardCore[s_type](t_userData, s_type, t_subTask.n_subTaskId, 1, t_subTask, t_autoAward)
			else
				mis_extend.share_mission_getaward_core(t_userData, s_type, t_subTask.n_subTaskId, 1, t_subTask, t_autoAward)
			end
		end
	end

	-- 发放普通道具
	if #t_autoAward.items > 0 then
		local n_code, s_desc = mis_data.add_items(t_user.n_uin, t_autoAward.items, s_type, 'auto_award')
		if n_code ~= t_retCode.n_OK then
			this.log( "awakening_mission add_items error|" .. t_user.n_uin .. '|' .. s_type .. '|' .. mis_uu.to_str(n_code) .. '|' .. mis_uu.to_str(s_desc) .. '|' .. mis_uu.to_str(t_autoAward))
		end
	end

	-- 业务逻辑延申处理
	if mis_extend.missionAward[s_type] then
		local n_code, s_desc = mis_extend.missionAward[s_type](t_user, t_userData, t_autoAward, t_resp, t_temp.n_exchange_type)
		if n_code ~= t_retCode.n_OK then
			this.log( "awakening_mission missionAward error|" .. t_user.n_uin .. '|' .. s_type .. '|' .. mis_uu.to_str(n_code) .. '|' .. mis_uu.to_str(s_desc) .. '|' .. mis_uu.to_str(t_autoAward))
		end
	end

	-- 客户端界面显示
	t_resp = t_resp or { tasks = {} }
	if t_resp.tasks then
		for k, v in pairs(t_userData.tasks[s_type] or {}) do
			t_resp.tasks[k] = { progress = v.progress, status = v.status, event = v.event, total = v.total }
		end
	end
	return true
end

this.share_mission_event_check = function (t_user, t_userData, t_resp)
	-- 自动领取奖励
	local ok, desc = share_mission_award_check(t_user, t_userData, t_resp)
	if not ok then
		mis_log.debug("share_mission_award_check fail : " .. desc)
	end
	-- 活动数据
	t_resp.profile = get_awakening_profile(t_user, t_userData)
	return t_retCode.n_OK
end

local cost_items = function ( t_user, t_userData, t_costItems, s_reason, s_exdata )
	local n_code, s_desc
	local t_itemCost = { items = {}, share = {}}
	for _, item in pairs(t_costItems or {}) do
		if itemFunc[item.id] then
			table_insert(t_itemCost.share, {id = item.id, num = item.num})
		else
			table_insert(t_itemCost.items, {id = item.id, num = item.num})
		end
	end

	local t_itemReady = { items = {}, share = {}}
	if mis_uu.tableNotEmpty(t_itemCost.share or {}) then
		n_code, s_desc = dec_awakening_item(t_userData, t_itemCost)
		if n_code ~= t_retCode.n_OK then
			return n_code, s_desc
		end
		t_itemReady.share = t_itemCost.share
	end

	for _, item in pairs(t_itemCost.items or {}) do
		n_code, s_desc = mis_bridge.cost_money(t_user.n_uin, item.id, item.num, mis_config.t_costType.n_ITEM, s_reason, s_exdata)
		if n_code ~= t_retCode.n_OK then
			this.log( 'awakening cost_money fail|' .. mis_uu.to_str({
				reason = s_reason,
				list = t_costItems,
				ready = t_itemReady,
				fault = item
			}))
			return n_code, s_desc
		end
		table_insert(t_itemReady.items, item)
	end

	return t_retCode.n_OK
end

local add_items = function (t_userData, t_awardItems)
	local t_itemList = { items = {}, share = {}}
	for _, item in pairs(t_awardItems or {}) do
		if itemFunc[item.id] then
			table_insert(t_itemList.share, {id = item.id, num = item.num})
		else
			table_insert(t_itemList.items, {id = item.id, num = item.num})
		end
	end

	if mis_uu.tableNotEmpty(t_itemList.share) then
		add_awakening_item(t_userData, t_itemList)
	end

	return t_itemList
end

local awakening_add_friend = function (src_uin, dst_uin)
	if tonumber(ngx.ctx.t_params.add_friend) ~= 1 then
		return
	end

	local n_code, s_desc = mis_bridge.force_make_friend(src_uin, dst_uin)
	if n_code ~= t_retCode.n_OK then
		this.log( 'code_exchange make friend fault' .. mis_uu.to_str({
			src_uin = src_uin,
			dst_uin = dst_uin,
			code = n_code,
			message = s_desc
		}))
	end
end

-- 兑换码结束后额外处理
this.share_mission_code_exchagne = function (t_user, t_userData, t_codeData, t_callbackData, rsp)
	-- 使用兑换码后加为好友
	awakening_add_friend(t_user.n_uin, t_codeData.uin)
end

this.upgrade_level = function ()
	local t_params 			= ngx.ctx.t_params
	local n_nowTime			= mis_data.get_server_time()

	local t_user = mis_data.get_user()
	local n_code, t_userData = t_user:get_awakening_activity_data()
	if n_code ~= t_retCode.n_OK then
		return n_code, 'get user data error'
	end

	t_userData.awakening = t_userData.awakening or new_awakening_profile()
	local t_taskConf = mis_data.t_awakening_activity
	t_userData.awakening.level = t_userData.awakening.level or 1
	if t_userData.awakening.level >= t_taskConf.t_conf.n_levelMax then
		return t_retCode.n_LEVEL_MAX_LIMIT, 'Level is max'
	end

	local nextLevel = t_userData.awakening.level + 1
	local levelConf = t_taskConf.t_conf.t_levelUp[nextLevel]
	if not levelConf then
		return t_retCode.n_WORK_ERR, 'level config not found'
	end

	local s_desc, t_items
	n_code, s_desc = cost_items(t_user, t_userData, levelConf.t_costItem, 'awakening_levelup',
	mis_common.table_to_json({aname = 'awakening_levelUp', level = nextLevel}))
	if n_code ~= t_retCode.n_OK then
		return n_code, s_desc
	end

	t_userData.awakening.level = t_userData.awakening.level + 1
	local t_itemList = add_items(t_userData, levelConf.t_awardItem)
	n_code, s_desc = t_user:set_awakening_activity_data(t_userData)
	if n_code ~= t_retCode.n_OK then
		return n_code, s_desc
	end

	update_cloud_server_room(t_user, t_userData)
	local s_type = mis_config.t_workType.s_AWAKENING_ACTIVITY
	if mis_uu.tableNotEmpty(t_itemList.items or {}) then
		n_code, s_desc, t_items = mis_data.add_items(t_user.n_uin, t_itemList.items, s_type, 'awakening_levelup')
		if n_code ~= t_retCode.n_OK then
			this.log( 'awakening add_items fault|' .. mis_uu.to_str({
				reason = 'awakening_levelup',
				list = t_itemList.items,
				fault = t_items,
				code = n_code,
				desc = s_desc,
			}))
		end
	end

	--埋点数据
	mis_log.remote_pure_day(mis_config.t_workType.s_AWAKENING_ACTIVITY, mis_common.table_to_json({
		key = 'levelup';
		ip = t_params.s_remoteAddr or ngx.ctx.xff or ngx.var.remote_addr or "nil";
		uin = t_params.uin;
		time = n_nowTime;
		country = t_params.country or 'nil';
		apiid = t_params.apiid or 'nil';
		ver = t_params.ver or 'nil';
		lang = t_params.lang or 'nil';
		type = s_type;
		bonus = t_itemList.t_items or 'nil';
		shares = t_itemList.share or 'nil';
		level  = t_userData.awakening.level;
	}))

	return t_retCode.n_OK, {
		profile  = get_awakening_profile(t_user, t_userData),
		getaward = levelConf.t_awardItem
	}
end

this.exchange_status = function ()
	local n_code, t_user, t_userData
	local t_taskConf = mis_data.t_awakening_activity
	if not(t_taskConf and t_taskConf.t_conf and t_taskConf.t_conf.t_store) then
		return t_retCode.n_WORK_ERR, 'The mission is not exist!'
	end

	t_user = mis_data.get_user()
	n_code, t_userData = t_user:get_awakening_activity_data(true)
	if n_code ~= t_retCode.n_OK then
		return n_code, 'get user data error'
	end

	local t_record = t_userData.record or {}

	-- TODO: 已兑换的电影票
	local t_resp = { exchange_num = t_userData.exchange_num or 0, t_remain = {}, tickets = {} }

	-- 电影票数据
	awakening_movies_status( t_user, t_userData, t_resp )

	-- 剩余可兑换次数
	local n_remian_ticket = tonumber(t_resp.tickets.remain) or 0
	for k, v in pairs(t_taskConf.t_conf.t_store.t_goods or {}) do
		if v.limit and v.limit > 0 then

			local t_good = {id = k, num = math_max(v.limit - (t_record[k] or 0), 0)}
			for _, t_goodItem in pairs(v.t_items or {}) do
				-- 以剩余电影票兑换码数量为准
				if  t_goodItem.id == mis_config.t_specialItem.s_SHARE
				and n_remian_ticket == 0 then
					t_good.num = 0
				end
			end
			table_insert(t_resp.t_remain, t_good)
		end
	end

	return t_retCode.n_OK, t_resp
end

local check_item_unique = function (uin, t_reward)
	local t_contentId = {}
	local b_exist 	  = false
	for _, v in pairs(t_reward.items or {}) do
		if v.id then table.insert(t_contentId, v.id) end
	end
	local n_code, ts_desc = mis_bridge.check_item_exist(uin, mis_common.table_to_json(t_contentId))
	if n_code ~= t_retCode.n_OK then
		this.log( "check_item_exist|" .. uin .. '|' .. mis_common.table_to_json(t_contentId))
		return n_code, ts_desc
	end
	for _, t_ in pairs(ts_desc or {}) do
		if t_.canget == false then
			b_exist = true
			break
		end
	end
	return b_exist
end

this.exchange = function ()
	local t_params 			= ngx.ctx.t_params
	local n_itemId 			= t_params.itemId
	local n_itemNum 		= t_params.itemNum
	local n_remainNum, n_price, n_total = 0, 0, 0

	local n_code, s_desc, t_tickets, t_user, t_userData, t_items
	local t_store, t_goods = {}, {}
	local n_nowTime		   = mis_data.get_server_time()

	local t_taskConf        = mis_data.t_awakening_activity
	if not(t_taskConf and t_taskConf.t_conf and t_taskConf.t_conf.t_store) then
		return t_retCode.n_WORK_ERR, 'The mission is not exist!'
	end

	t_store = t_taskConf.t_conf.t_store
	if n_nowTime < t_store.n_startTime or n_nowTime > t_store.n_endTime then
		this.log( "invalid time|" .. t_params.uin .. '|' .. t_store.n_startTime .. '|' .. t_store.n_endTime)
		return t_retCode.n_OPER_ERR, 'invalid time'
	end
	if n_itemId <= 0 and n_itemNum <= 0 then
		this.log( "param error|" .. t_params.uin .. '|' .. n_itemId .. '|' .. n_itemNum)
		return t_retCode.n_PARAM_ERR, 'param error'
	end
	if not (t_store.t_goods and t_store.t_goods[n_itemId] and t_store.t_goods[n_itemId].price and
			t_store.t_goods[n_itemId].t_items and mis_uu.tableNotEmpty(t_store.t_goods[n_itemId].t_items)) then
		return t_retCode.n_PARAM_ERR, 'goods is not exist'
	end

	t_user = mis_data.get_user()
	n_code, t_userData = t_user:get_awakening_activity_data()
	if n_code ~= t_retCode.n_OK then
		return n_code, 'get user data error'
	end

	t_goods   	= t_store.t_goods[n_itemId]
	n_price   	= t_goods.price
	n_total   	= n_itemNum * n_price
	n_remainNum = tonumber(t_userData.exchange_num or 0)

	if n_total > n_remainNum or n_total <= 0 then
		this.log( "num not enough|" .. t_params.uin .. '|' .. n_total .. '|' .. n_remainNum)
		return t_retCode.n_PARAM_ERR, 'exchange num is not enough'
	end

	local t_reward = { items = {}}
	for k, v in pairs(t_goods.t_items or {}) do
		if v.id and v.num then
			local t_item = mis_uu.table_value_copy(v)
			t_item.num = v.num * n_itemNum

			if itemFunc[t_item.id] then
				-- 商城兑换不可能兑换自身所以这里复用了s_SHARE来代表电影票
				if t_item.id == mis_config.t_specialItem.s_SHARE then
					if v.num ~= 1 then
						return t_retCode.n_WORK_ERR, 'invalid config'
					end
					t_reward.tickets = t_item.num
				else
					table_insert(t_reward.items, t_item)
				end
			else
				table_insert(t_reward.items, t_item)
			end
		end
	end
	t_userData.record 			= t_userData.record or {}
	t_userData.record[n_itemId] = t_userData.record[n_itemId] or 0
	t_userData.record[n_itemId] = t_userData.record[n_itemId] + n_itemNum

	-- 兑换次数限制
	if t_goods.limit and t_goods.limit > 0 and t_userData.record[n_itemId] > t_goods.limit then
		this.log( "exceed the limit|" .. t_params.uin .. '|' .. n_itemId .. '|' .. t_goods.limit)
		return t_retCode.n_PARAM_ERR, 'exceed the limit'
	end

	-- 已拥有不予兑换，帐号服校验
	if t_goods.unique and t_goods.unique == 1 and not check_item_unique(t_params.uin, t_reward) then
		this.log( "already owned|" .. t_params.uin .. '|' .. mis_common.table_to_json(t_reward))
		return t_retCode.n_OPER_ERR, 'already owned'
	end

	-- 生成电影票订单
	if t_reward.tickets and t_reward.tickets > 0 then
		if t_reward.tickets ~= 1 then
			return t_retCode.n_OPER_ERR, 'change ticket one by one'
		end

		t_tickets, n_code = create_movie_tickets(t_user.n_uin)
		if n_code then
			return n_code, 'create_movie_tickets fault'
		end

		-- 记录已获得的电影票券
		for _, cdkey in pairs(t_tickets or {}) do
			t_userData.movies = t_userData.movies or {}
			t_userData.movies.tickets = t_userData.movies.tickets or {}
			t_userData.movies.tickets[#t_userData.movies.tickets + 1] = cdkey
		end
		if n_itemNum ~= #t_tickets then
			n_itemNum = #t_tickets
			n_total   = n_itemNum * n_price
		end
	end

	-- 扣除兑奖券
	t_userData.exchange_num = n_remainNum - n_total
	local t_itemList = add_items(t_userData, t_reward.items)
	n_code, s_desc = t_user:set_awakening_activity_data(t_userData)
	if n_code ~= t_retCode.n_OK then
		return n_code, s_desc
	end

	local s_type = mis_config.t_workType.s_AWAKENING_ACTIVITY
	if mis_uu.tableNotEmpty(t_itemList.items or {}) then
		n_code, s_desc, t_items = mis_data.add_items(t_user.n_uin, t_itemList.items, s_type, 'awakening_exchagne')
		if n_code ~= t_retCode.n_OK then
			this.log( 'awakening add_items fault|' .. mis_uu.to_str({
				reason = 'awakening_exchagne',
				list   = t_itemList.items,
				fault  = t_items,
				code   = n_code,
				desc   = s_desc,
			}))
		end
	end

	--埋点数据
	mis_log.remote_pure_day(s_type, mis_common.table_to_json({
		key     = 'store_exchange';
		ip      = t_params.s_remoteAddr or ngx.ctx.xff or ngx.var.remote_addr or "nil";
		uin     = t_params.uin;
		time    = n_nowTime;
		country = t_params.country or 'nil';
		apiid   = t_params.apiid or 'nil';
		ver     = t_params.ver or 'nil';
		lang    = t_params.lang or 'nil';
		bonus   = t_goods.t_items or 'nil';
		tickets = t_tickets;
	}))

	return t_retCode.n_OK, { num = n_remainNum - n_total, t_goods = t_goods.t_items, t_tickets = t_tickets }
end

this.get_rank_top = function ()
	local t_params = ngx.ctx.t_params
	local n_uin    = t_params.uin
	local s_mapID  = t_params.mapId
	local version  = t_params.rank_ver
	local n_page   = tonumber(t_params.page) or 1

	local ranking = get_map_ranking(s_mapID)
	if not ranking then
		return t_retCode.n_WORK_ERR, 'rank instance not found'
	end

	-- 角色自身缓存数据 
	local t_user = mis_data.get_user()
	local n_code, t_userData = t_user:get_awakening_activity_data(true)
	if n_code ~= t_retCode.n_OK then
		return n_code, 'get user data error'
	end

	t_userData.map = t_userData.map or {}
	t_userData.map[s_mapID] = t_userData.map[s_mapID] or {}

	-- 组装消息数据
	local t_rankTop = ranking:Get() or {}
	local n_pageCnt = version and version ~= t_rankTop.version and 1 or n_page
	local rsp = {
		rank    = {},                 -- 一页榜单数据
		page    = n_pageCnt,		  -- 当前是第几页
		total   = t_rankTop.total,    -- 可展示榜单数
		version = t_rankTop.version,  -- 榜单版本信息
		self    = {                   -- 自己的排名信息
			rank  = -1,             -- 不在前100名榜单内
			value = t_userData.map[s_mapID].rankValue or 0
		}
	}
	-- 每页返回20个玩家数据
	local start = (n_pageCnt - 1) * 20 + 1
	local final =  n_pageCnt * 20
	for top, role in pairs(t_rankTop.rank or {}) do
		if top >= start and top <= final then
			rsp.rank[top] = role
		end
		if tonumber(role.uid) == n_uin then
			rsp.self.rank  = top
			rsp.self.value = role.value
		end
	end

	return t_retCode.n_OK, rsp
end

local update_role_map_value = function (t_user, t_userData, t_rankConf, s_mapID, n_value)
	-- 角色自身缓存数据
	t_userData.map = t_userData.map or {}
	t_userData.map[s_mapID] = t_userData.map[s_mapID] or {}
	-- TODO: 这块的逻辑应该挪入排汗榜模块内
	if t_rankConf.updates == mis_rank.Updates.FullVolume then
		if t_rankConf.order_by == mis_rank.OrderBy.ASC then
			local rankValue = tonumber(t_userData.map[s_mapID].rankValue)
			t_userData.map[s_mapID].rankValue = not rankValue and n_value or math_min(n_value, rankValue)
		else
			local rankValue = tonumber(t_userData.map[s_mapID].rankValue) or 0
			t_userData.map[s_mapID].rankValue = math_max(n_value, rankValue)
		end
	else
		t_userData.map[s_mapID].rankValue = t_userData.map[s_mapID].rankValue or 0
		t_userData.map[s_mapID].rankValue = t_userData.map[s_mapID].rankValue + n_value
	end
	local n_code, s_desc = t_user:set_awakening_activity_data(t_userData)
	if n_code ~= t_retCode.n_OK then
		return n_code, s_desc
	end

	return t_retCode.n_OK
end

this.update_rank = function ()
	local t_params   = ngx.ctx.t_params
	local n_uin      = t_params.uin
	local n_updates  = t_params.updates
	local s_mapID    = t_params.mapId
	local n_value    = tonumber(t_params.value)

	if not n_value or n_value < 0 then
		return t_retCode.n_PARAM_ERR
	end

	-- 龙之塔 拒绝 200 秒过关
	if s_mapID == "8138963026934" and n_value < 200 then
		this.log(mis_uu.to_str({ uin = n_uin, map = s_mapID, value = n_value}))
		return t_retCode.n_PARAM_ERR
	end

	-- 活动校验
	local n_nowtime  = mis_data.get_server_time()
	local t_taskConf = mis_data.t_awakening_activity
	if not (t_taskConf.t_conf and t_taskConf.t_conf.t_map) then
		return t_retCode.n_WORK_ERR
	end
	local t_mapConf = t_taskConf.t_conf.t_map[s_mapID]
	if not t_mapConf then
		return t_retCode.n_PARAM_ERR, 'invalid map'
	end
	if t_mapConf.n_startTime > n_nowtime
	or t_mapConf.n_endTime   < n_nowtime then
		return t_retCode.n_OPER_ERR, 'not activity time'
	end

	-- 榜单配置
	local t_rankConf = t_taskConf.t_conf.t_rank[s_mapID] or {}
	if mis_uu.tableIsEmpty(t_rankConf) then
		return t_retCode.n_OPER_ERR, 'no rank conf'
	end
	if n_updates ~= t_rankConf.updates then
		return t_retCode.n_OPER_ERR, 'invalid updates'
	end

	local n_code, s_desc, t_userData
	local t_user = mis_data.get_user()
	n_code, t_userData = t_user:get_awakening_activity_data()
	if n_code ~= t_retCode.n_OK then
		return n_code, 'get user data error'
	end

	local oldValue = t_userData.map[s_mapID].rankValue
	n_code, s_desc = update_role_map_value(t_user, t_userData, t_rankConf, s_mapID, n_value)
	if n_code ~= t_retCode.n_OK then
		return n_code, s_desc
	end

	local t_profile = {
		rolename  = t_params.rolename,
		portrait  = t_params.portrait,
		headframe = t_params.headframe,
	}
	local newValue = oldValue ~= t_userData.map[s_mapID].rankValue and t_userData.map[s_mapID].rankValue or nil
	local ranking  = get_map_ranking(s_mapID)
	if not ranking or not ranking:Set( n_uin, newValue, t_profile ) then
		return t_retCode.n_PARAM_ERR
	end

	return t_retCode.n_OK
end

this.get_mapaward = function ()
	local t_params   = ngx.ctx.t_params
	local s_mapID    = t_params.mapId
	local s_itemID   = t_params.id
	local n_num      = t_params.num

	if not n_num or n_num <= 0 then
		return t_retCode.n_PARAM_ERR, 'invalid num'
	end

	-- 活动校验
	local n_nowtime  = mis_data.get_server_time()
	local t_taskConf = mis_data.t_awakening_activity
	if not (t_taskConf.t_conf and t_taskConf.t_conf.t_map) then
		return t_retCode.n_WORK_ERR
	end
	local t_mapConf = t_taskConf.t_conf.t_map[s_mapID]
	if not t_mapConf then
		return t_retCode.n_PARAM_ERR
	end
	if t_mapConf.n_startTime > n_nowtime
	or t_mapConf.n_endTime   < n_nowtime then
		return t_retCode.n_OPER_ERR, 'not activity time'
	end
	local t_limitConf = t_mapConf.t_awardLimit[s_itemID]
	if not t_limitConf then
		return t_retCode.n_PARAM_ERR, 'invalid award ID'
	end

	local t_user = mis_data.get_user()
	local n_code, t_userData = t_user:get_awakening_activity_data(true)
	if n_code ~= t_retCode.n_OK then
		return n_code, 'get user data error'
	end

	-- 初始化
	t_userData.map = t_userData.map or {}
	t_userData.map[s_mapID] = t_userData.map[s_mapID] or {}
	t_userData.map[s_mapID].awardLimit = t_userData.map[s_mapID].awardLimit or {}
	t_userData.map[s_mapID].awardLimit[s_itemID] = t_userData.map[s_mapID].awardLimit[s_itemID] or {
		count = 0,
		refreshTime = n_nowtime,
	}

	-- 刷新数据
	local t_itemLimit = t_userData.map[s_mapID].awardLimit[s_itemID]
	if t_limitConf.b_dailyLimit and mis_common.is_another_day(t_itemLimit.refreshTime, n_nowtime) then
		t_itemLimit.count = 0
		t_itemLimit.refreshTime = n_nowtime
	end

	mis_uu.var_dump({
		limit = t_limitConf.n_limit,
		count = t_itemLimit.count,
		add   = n_num,
		mapID = s_mapID,
		itemID = s_itemID,
	})

	if t_itemLimit.count + n_num >= t_limitConf.n_limit then
		n_num = math_max(t_limitConf.n_limit - t_itemLimit.count, 0)
	end
	if n_num <= 0 then
		return t_retCode.n_OK, { profile = get_awakening_profile(t_user, t_userData) }
	end

	t_itemLimit.count = t_itemLimit.count + n_num
	t_itemLimit.refreshTime = n_nowtime

	local s_desc, t_items
	local t_itemList = add_items(t_userData, {{id = s_itemID, num = n_num}})
	n_code, s_desc = t_user:set_awakening_activity_data(t_userData)
	if n_code ~= t_retCode.n_OK then
		return n_code, s_desc
	end

	local s_type = mis_config.t_workType.s_AWAKENING_ACTIVITY
	t_itemList.items = mis_uu.tableNotEmpty(t_itemList.items) and t_itemList.items or nil
	if t_itemList.items then
		n_code, s_desc, t_items = mis_data.add_items(t_user.n_uin, t_itemList.items, s_type, 'awakening_add_money')
		if n_code ~= t_retCode.n_OK then
			this.log( 'awakening add_items fault|' .. mis_uu.to_str({
				reason = 'awakening_levelup',
				list = t_itemList.items,
				fault = t_items,
				code = n_code,
				desc = s_desc,
			}))
		end
	end

	--埋点数据
	mis_log.remote_pure_day(mis_config.t_workType.s_AWAKENING_ACTIVITY, mis_common.table_to_json({
		key     = 'getaward';
		ip      = t_params.s_remoteAddr or ngx.ctx.xff or ngx.var.remote_addr or "nil";
		uin     = t_params.uin;
		time    = n_nowtime;
		country = t_params.country or 'nil';
		apiid   = t_params.apiid or 'nil';
		ver     = t_params.ver or 'nil';
		lang    = t_params.lang or 'nil';
		bonus   = t_itemList.items or 'nil';
		shares  = t_itemList.share or 'nil';
		mapid   = s_mapID,
	}))

	return t_retCode.n_OK, { profile = get_awakening_profile(t_user, t_userData), items = t_itemList.items }
end


this.pre_awakening_activity = function ()
	local t_params  		= ngx.ctx.t_params
	local t_taskConf 		= mis_data.t_awakening_activity
	local n_nowtime 		= mis_data.get_server_time()

	if t_taskConf.n_status ~= mis_config.t_workStatus.n_ENABLE then
		this.log( "pre_awakening_activity status disable|" .. t_params.uin)
		return t_retCode.n_OPER_ERR, 'awakening_activity disable'
	end

	if not t_taskConf
	or not t_taskConf.t_conf
	or not t_taskConf.t_conf.n_levelMax
	or not t_taskConf.t_conf.t_levelUp
	or not t_taskConf.t_conf.t_store
	or not t_taskConf.t_conf.t_rank
	or not t_taskConf.t_conf.t_map then
		return t_retCode.n_WORK_ERR, 'Config load fault'
	end

	-- 活动有效期间
	if n_nowtime < t_taskConf.t_conf.n_startTime or n_nowtime > t_taskConf.t_conf.n_endTime then
		this.log( "pre_awakening_activity out of time|" .. t_params.uin)
		return t_retCode.n_OPER_ERR, 'Activity is out of validity!'
	end

	-- 渠道控制
	if mis_uu.tableNotEmpty(t_taskConf.t_conf.t_apiids) then
		local b_valid_apiid  = false
		local n_apiid  =  tonumber(t_params.apiid or 0)

		for _, v in pairs(t_taskConf.t_conf.t_apiids or {}) do
			if v and tonumber(v) == n_apiid then
				b_valid_apiid = true
				break
			end
		end
		if not b_valid_apiid then
			this.log( "pre_awakening_activity apiid is invalid|" .. t_params.uin ..  "|" .. n_apiid)
			return t_retCode.n_OPER_ERR, 'apiid is invalid'
		end
	end

	if mis_uu.tableNotEmpty(t_taskConf.t_conf.t_noapiids) then
		local b_valid_apiid  = false
		local n_apiid  =  tonumber(t_params.apiid or 0)

		for _, v in pairs(t_taskConf.t_conf.t_apiids or {}) do
			if v and tonumber(v) == n_apiid then
				b_valid_apiid = true
				break
			end
		end
		if b_valid_apiid then
			this.log( "pre_awakening_activity noapiid is invalid|" .. t_params.uin .. '|' .. n_apiid)
			return t_retCode.n_OPER_ERR, 'apiid is invalid - ' .. n_apiid
		end
	end

	-- 版本号控制
	local n_l = mis_common.version_to_number(t_params.ver or 0)
	local n_r = t_taskConf.t_conf.n_version_min
	if n_l < n_r then
		this.log( "pre_awakening_activity version too low|" .. t_params.uin .. '|' .. n_l)
		return t_retCode.n_OPER_ERR, 'version too low'
	end

	return t_retCode.n_OK
end

this.setting_item = function ()
	local t_params  		= ngx.ctx.t_params
	local n_uin             = t_params.uin
	local b_dsc             = t_params.dsc
	local s_itemID          = t_params.itemid
	local n_itemNum         = t_params.itemnum

	local n_code, s_desc = this.pre_awakening_activity()
	if n_code ~= t_retCode.n_OK then
		return n_code, s_desc
	end

	local t_user, t_userData = mis_data.get_user(n_uin), nil
	n_code, t_userData = t_user:get_awakening_activity_data()
	if n_code ~= t_retCode.n_OK then
		return n_code, 'get user data error'
	end

	local OP = b_dsc and itemOp.DEC or itemOp.ADD
	if  itemFunc[s_itemID]
	and itemFunc[s_itemID][OP] then
		-- 增加
		n_code, s_desc = itemFunc[s_itemID][OP](t_userData, { id = s_itemID, num = n_itemNum })
		if n_code ~= t_retCode.n_OK then
			return n_code, s_desc
		end

		-- 保存
		n_code, s_desc = t_user:set_awakening_activity_data(t_userData)
		if n_code ~= t_retCode.n_OK then
			return n_code, s_desc
		end

		return t_retCode.n_OK, get_awakening_profile(t_user, t_userData)
	end

	if OP == itemOp.DEC then
		return t_retCode.n_OPER_ERR, 'can not del user items'
	end

	local t_item = {{ id = s_itemID, num = n_itemNum }}
	local s_type = mis_config.t_workType.s_AWAKENING_ACTIVITY
	return mis_data.add_items(t_user.n_uin, t_item, s_type, 'gm_add_items')
end

this.update_could_room_dhs = function ()
	local n_code, s_desc = this.pre_awakening_activity()
	if n_code ~= t_retCode.n_OK then
		return n_code, s_desc
	end

	local t_user, t_userData = mis_data.get_user(), nil
	n_code, t_userData = t_user:get_awakening_activity_data(true)
	if n_code ~= t_retCode.n_OK then
		return n_code, 'get user data error'
	end

	if not update_cloud_server_room(t_user, t_userData) then
		return t_retCode.n_OPER_ERR, 'update failt'
	end

	return t_retCode.n_OK
end

this.reset_awakening_data = function ()
	local t_params  		= ngx.ctx.t_params
	local n_uin             = t_params.uin
	local t_user = mis_data.get_user(n_uin)
	local n_code, t_userData = t_user:get_awakening_activity_data()
	if n_code ~= t_retCode.n_OK then
		return n_code, 'get user data error'
	end

	local s_desc
	n_code, s_desc = t_user:set_awakening_activity_data({})
	if n_code ~= t_retCode.n_OK then
		return n_code, s_desc
	end

	this.log(mis_uu.to_str({reason = 'reset_awakening_data', uin = n_uin, backup = t_userData}))
	return t_retCode.n_OK
end

this.pop_awakening_ticket = function ()
	local t_params  		= ngx.ctx.t_params
	local n_uin             = t_params.uin
	local passwd            = t_params.pw

	if passwd ~= 'alibabazimakaimen' then
		return t_retCode.n_PARAM_ERR
	end

	local t_user = mis_data.get_user(n_uin)
	local n_code, t_userData = t_user:get_awakening_activity_data()
	if n_code ~= t_retCode.n_OK then
		return n_code, 'get user data error'
	end

	local t_tickets, n_code = create_movie_tickets(t_user.n_uin, 1)
	if n_code then
		return n_code, 'create_movie_tickets fault'
	end

	-- 记录已获得的电影票券
	for _, cdkey in pairs(t_tickets or {}) do
		t_userData.movies = t_userData.movies or {}
		t_userData.movies.tickets = t_userData.movies.tickets or {}
		t_userData.movies.tickets[#t_userData.movies.tickets + 1] = cdkey
	end

	this.log(mis_uu.to_str({reason = 'pop_awakening_ticket', uin = n_uin, tickets = t_tickets}))

	local s_desc
	n_code, s_desc = t_user:set_awakening_activity_data(t_userData)
	if n_code ~= t_retCode.n_OK then
		return n_code, s_desc
	end
	return t_retCode.n_OK, t_tickets
end

this.fix_rank_value = function ()
	local t_params = ngx.ctx.t_params
	local mapid    = t_params.id
	local n_uin    = t_params.uin

	local ranking = get_map_ranking(mapid)
	if not ranking then
		return t_retCode.n_WORK_ERR, 'rank instance not found'
	end

	local n_code, s_desc, t_userData
	local t_user = mis_data.get_user(n_uin)
	n_code, t_userData = t_user:get_awakening_activity_data()
	if n_code ~= t_retCode.n_OK then
		return n_code, 'get user data error'
	end

	if  t_userData.map
	and t_userData.map[mapid]
	and t_userData.map[mapid].rankValue then
		t_userData.map[mapid].rankValue = nil
	end

	n_code, s_desc = t_user:set_awakening_activity_data(t_userData)
	if n_code ~= t_retCode.n_OK then
		return n_code, s_desc
	end

    local succ, info = ranking:Del(n_uin)
    if not succ then
        return t_retCode.n_OPER_ERR, info
    end

    this.log(mis_uu.to_str({ msg = "fix user rank", mapid = mapid, uin = n_uin, del_cnt = info}))
    return true, info
end

this.drop_from_rank = function ()
	local t_params = ngx.ctx.t_params
	local mapid    = t_params.id
	local n_uin    = t_params.uin

	local ranking = get_map_ranking(mapid)
	if not ranking then
		return t_retCode.n_WORK_ERR, 'rank instance not found'
	end

    local succ, info = ranking:Del(n_uin)
    if not succ then
        return t_retCode.n_OPER_ERR, info
    end

    this.log(mis_uu.to_str({ msg = "drop user rank", mapid = mapid, uin = n_uin, del_cnt = info}))
    return true, info
end

-- 说明：模块包含
-- 参数：模块表
this.modules_include = function(t_moddules)
	mis_data     = t_moddules.mis_data
	mis_log      = t_moddules.mis_log
	mis_bridge   = t_moddules.mis_bridge
	mis_common   = t_moddules.mis_common
	mis_extend   = t_moddules.mis_extend
	mis_config   = t_moddules.mis_config
	t_retCode    = mis_config.t_retCode
	t_retCodeMsg = mis_config.t_retCode_Msg
end

return this